 /*
 * @name: 运费弹窗选择区域
 * @Author: along
 * @Date: 2020-06-20
 * @Last Modified by: mikey.zhaopeng
 * @Last Modified time: 2021-04-12 09:11:05
 */
<template>
    <div
        class="dialogVisible"
        v-if="dialogVisible"
    >
        <div
            width="640px"
            class="zd-region-dialog"
        >
            <div class="zd-region-dialog-head">
                <p class="zd-region-dialog-head-title">
                    选择区域
                </p>
                <span
                    class="el-icon-close"
                    @click="dialogVisible = false"
                />
            </div>
            <div class="zd-city">
                <div
                    v-for="(item,index) in datalist"
                    :key="index"
                    class="zd-list"
                >
                    <div class="zd-list-left">
                        <el-checkbox
                            v-model="checkAll"
                            :label="item.name"
                            @change="handleCheckAllChange(checkAll[checkAll.length - 1], item.name, item)"
                            :disabled="item.off"
                        >
                            {{ item.name }}
                        </el-checkbox>
                    </div>
                    <div class="zd-list-right">
                        <el-checkbox-group
                            v-model="checkProvide"
                        >
                            <el-checkbox
                                v-for="(city,i) in item.list"
                                :label="city.name"
                                :key="i"
                                :disabled="city.off"
                                @mouseenter.native="fnEnterCheck(city, i)"
                                @mouseleave.native="fnLeaveCheck(city)"
                                @change="handleCheckedCitiesChange(checkProvide[checkProvide.length - 1], city.name, city)"
                                :class="city.list.length == 1 ? 'zd-checkbox-width' : ''"
                            >
                                <div class="zd-list-city">
                                    {{ city.name }}
                                    <span
                                        v-if="city.length"
                                        class="zd-list-city-length"
                                    >
                                        ({{ city.length }})
                                    </span>
                                    <i
                                        class="el-icon-caret-bottom"
                                        :style="{ transform: city.flag ? `rotate(180deg)` : '' }"
                                    />
                                    <div
                                        :class="index >= 6 ? 'zd-hover-top' : 'zd-hover' "
                                        v-if="i == now_index && city.flag"
                                    >
                                        <el-checkbox-group
                                            v-model="cityAll"
                                        >
                                            <el-checkbox
                                                v-for="(option,key) in city.list"
                                                :label="option.id"
                                                :key="key"
                                                :disabled="option.flag"
                                                @change="handleCityChange(city.list, city.name, city)"
                                            >
                                                {{ option.name | setName }}
                                            </el-checkbox>
                                        </el-checkbox-group>
                                    </div>
                                </div>
                            </el-checkbox>
                        </el-checkbox-group>
                    </div>
                </div>
            </div>

            <div class="zd-foot">
                <el-button
                    size="small"
                    type="default"
                    style="width:126px;height:36px"
                    @click="dialogVisible = false"
                >
                    取消
                </el-button>
                <el-button
                    size="small"
                    type="primary"
                    style="width:126px;height:36px;margin-left:51px"
                    @click="fnSave()"
                >
                    保存
                </el-button>
            </div>
        </div>
    </div>
</template>

<script>
export default {
    data () {
        return {
            dialogVisible: false,//弹窗开关
            datalist: [], //区域数据
            checkAll: [],//大区选中数据，只做区分
            checkProvide: [],//省份选择数据，只做区分
            cityAll: [],//城市选中数据id,最终需要数据
            now_index: -1,
            cityList: [],//对区域数据过滤，取所有城市数据
            checkPart: [],//编辑时生效,其它模版数据，等同不可编辑的数据
            list: [],//编辑时使用,选择的所有数据
            checkList: [],//编辑时使用,当前模版选择的数据
            type: '',//类型 add_region/add_city:新增 edit:编辑
            editIndex: '',//编辑数据索引
            param: '',//区分编辑数据类型
        };
    },
    filters: {
        setName (val) {
            if(val.length > 4) {
                return val.slice(0,4) + '...';
            } else {
                return val;
            }
        }
    },
    created () {
        this.getList();
    },
    methods: {
        /**
         * 重置状态
         */
        getDialogType (val, param) {
            this.type = val;
            this.param = param;
            this.checkProvide = this.checkAll = this.cityAll = [];

            this.datalist.forEach(element => {
                element.off = false;
                element.list.forEach(option => {
                    option.length = 0;
                    option.off = false;
                    option.list.forEach(item => {
                        item.flag = false;
                    });
                });
            });
        },

        /**
         * 编辑弹窗
         * @param   {Array}      listALl        //全部模版已选择城市数据
         * @param   {Array}      list           //当前模版已选择数据
         * @param   {Number}     editIndex      //编辑数据的索引，用于回填
         */
        getEditList (listALl, list, index) {
            this.list = listALl;
            this.checkList = list;
            this.editIndex = index;
            this.getCityList();//城市数据回填
            this.getProvide(this.list, this.checkList);//省份数据回填
        },

        /**
         * 新增配送方式时数据处理
         */
        setData (list) {
            this.list = list;
            this.checkList = [];
            this.param = true;
            this.getCityList();//城市数据回填
            this.getProvide(this.list, []);//省份数据回填
        },

        /**
         * 获取运费区域列表
         */
        getList () {
            this.$post('/FreightZone/lists',{}, resp=>{
                if(resp.code == 1) {
                    this.datalist = resp.data.list;

                    this.datalist.forEach(element => {
                        element.list.forEach(option => {
                            this.cityList = this.cityList.concat(option.list);
                        });
                    });
                }
            });

            this.datalist.forEach(element => {
                element.list.forEach(option => {
                    this.cityList = this.cityList.concat(option.list);
                });
            });
        },


        /**
         * 打开弹窗
         */
        show () {
            this.dialogVisible = true;
        },

        /**
         * 城市数据回填
         * 分析
         *       1.其它模版选择过的区域不可选择，取差集
         *       2.回填自己选择的数据
         */
        getCityList () {
            let dataList = [];

            let checkCity = this.list.reduce((cur,next) => {//已选择的所有数据
                cur.push(next.id);
                return cur;
            },[]);

            let checkDisabledCity = this.checkList.reduce((cur,next) => {//当前模版的数据
                cur.push(next.id);
                return cur;
            },[]);

            let checkPart = checkCity.filter(item => !checkDisabledCity.includes(item));//不可编辑的回填数据

            this.checkPart = checkPart;
            this.cityAll = checkPart.concat(checkDisabledCity);

            this.datalist.forEach(element => {//处理不可编辑的数据
                element.list.forEach(option => {
                    let list = option.list.reduce((cur,next) => {
                        cur.push(next.id);
                        return cur;
                    },[]);

                    option.length = list.filter(item => this.cityAll.includes(item)).length;//回填数量
                    option.list.forEach(item => {//勾选状态
                        checkPart.forEach(next => {
                            if(item.id == next && this.param) {
                                item.flag = true;
                            }
                        });
                    });
                    option.list.forEach(item => {//勾选状态
                        checkDisabledCity.forEach(next => {
                            if(item.id == next) {
                                item.flag = false;
                            }
                        });
                    });
                });
            });
        },

        /**
         * 回填省份
         * 分析
         *      1.选中数据必须大于当前省份的所有城市数据
         *      2.当前省份的所有城市在选中数据里
         */
        getProvide (list, checkList) {
            let data = JSON.parse(JSON.stringify(this.datalist));
            let arr = list.reduce((cur,next) => {
                cur.push(next.id);
                return cur;
            },[]);

            for(let key=0; key<data.length;key++) {
                let cityList = data[key].list;

                for(let i=0; i<cityList.length; i++) {
                    if(cityList[i].list.length <= arr.length) {
                        let city = cityList[i].list.reduce((cur,next) => {
                            cur.push(next.id);
                            return cur;
                        },[]);
                        let flag = city.filter(item => arr.includes(item));

                        if(flag.length == city.length) {
                            this.checkProvide.push(cityList[i].name);
                        }
                    }
                }
            }

            for(let i=0; i<this.datalist.length; i++) {//省份禁止选择
                let provideList = this.datalist[i].list;

                for(let j=0; j<provideList.length; j++) {
                    if(this.checkProvide.includes(provideList[j].name) && this.param) {
                        provideList[j].off = true;
                    }
                }
            }

            this.setProvideEdit(checkList);//处理选择省份可编辑
            this.getRegion(this.checkProvide);//大区数据回填
        },

        /**
         * 处理可选择省份
         */
        setProvideEdit (list) {
            let checkProvide = [];
            let data = JSON.parse(JSON.stringify(this.datalist));
            let arr = list.reduce((cur,next) => {
                cur.push(next.id);
                return cur;
            },[]);

            for(let key=0; key<data.length;key++) {
                let cityList = data[key].list;

                for(let i=0; i<cityList.length; i++) {
                    if(cityList[i].list.length <= arr.length) {
                        let city = cityList[i].list.reduce((cur,next) => {
                            cur.push(next.id);
                            return cur;
                        },[]);
                        let flag = city.filter(item => arr.includes(item));

                        if(flag.length == city.length) {
                            checkProvide.push(cityList[i].name);
                        }
                    }
                }
            }

            for(let i=0; i<this.datalist.length; i++) {//省份可以选择
                let provideList = this.datalist[i].list;

                for(let j=0; j<provideList.length; j++) {
                    if(checkProvide.includes(provideList[j].name) && this.param) {
                        provideList[j].off = false;
                    }
                }
            }

            setTimeout(()=>{
                this.setRegionEdit(checkProvide);//已选数据大区可以选择,这里数据存在异步更新
            },30);
        },

        /**
         * 大区数据回填
         */
        getRegion (provide) {
            let data = JSON.parse(JSON.stringify(this.datalist));

            for(let key=0;key<data.length; key++){
                let cityList = data[key].list;
                let provideAll = cityList.reduce((cur,next) => {
                    cur.push(next.name);
                    return cur;
                },[]);

                let flag = provideAll.filter(item => provide.includes(item));

                if(flag.length == provideAll.length) {
                    this.checkAll.push(data[key].name);
                }
            }

            for(let i=0; i<this.datalist.length; i++) {//大区禁止选择

                if(this.checkAll.includes(this.datalist[i].name) && this.param) {
                    this.datalist[i].off = true;
                }
            }
        },

        /**
         * 大区可以选择
         */
        setRegionEdit (provide) {
            let data = JSON.parse(JSON.stringify(this.datalist));
            let checkAll = [];


            for(let key=0;key<data.length; key++){
                let cityList = data[key].list;
                let provideAll = cityList.reduce((cur,next) => {
                    cur.push(next.name);
                    return cur;
                },[]);

                let flag = provideAll.filter(item => provide.includes(item));

                if(flag.length == provideAll.length) {
                    checkAll.push(data[key].name);
                }
            }

            for(let i=0; i<this.datalist.length; i++) {//大区可以选择

                if(checkAll.includes(this.datalist[i].name) && this.param) {
                    this.datalist[i].off = false;
                }
            }

            this.datalist = this.datalist.slice();//处理虚拟dom无法重绘
        },

        /**
         * 大区全选与取消全选
         * 分析
         *      全选：数据并集,合并元素即可
         *      取消全选：差集 = 并集 - 交集
         *      交集：数组重复的元素
         */
        handleCheckAllChange(old_name, new_name, row) {
            if(old_name == new_name) {//全选大区下所有市

                for(let key=0; key<this.datalist.length; key++) {
                    if(new_name == this.datalist[key].name) {
                        let provideList = this.datalist[key].list;

                        for(let i=0; i<provideList.length; i++) {

                            this.checkProvide.push(//选中大区下所有省
                                provideList[i].name
                            );
                            let cityList = provideList[i].list;

                            for(let j=0; j<cityList.length; j++) {
                                this.cityAll.push(//选中大区下所有市
                                    cityList[j].id
                                );
                            }
                        }
                    }
                }

                for(let key=0; key<row.list.length; key++) {//数量计算
                    this.$set(row.list[key], 'length', row.list[key].list.length);
                }
            } else { //取消全选,
                let checkProvide = [];//存储取消选择的省份
                let checkCity = [];//存储取消选择的城市

                for(let key=0; key<this.datalist.length; key++) {
                    if(new_name == this.datalist[key].name) {
                        let provideList = this.datalist[key].list;

                        for(let i=0; i<provideList.length; i++) {
                            let cityList = provideList[i].list;

                            checkProvide.push(provideList[i].name);

                            for(let j=0; j<cityList.length; j++) {
                                if(this.cityAll.indexOf(cityList[j].id) > -1) {
                                    checkCity.push(cityList[j].id);
                                }
                            }
                        }
                    }
                }
                this.checkProvide = this.checkProvide.filter(item => !checkProvide.includes(item));//省份数据处理
                this.cityAll = this.cityAll.filter(item => !checkCity.includes(item));//城市数据处理

                for(let key=0; key<row.list.length; key++) {//数量计算
                    this.$set(row.list[key], 'length', 0);
                }
            }
        },

        /**
         * 选择省份
         * 分析
         *      全选省份下所有市：并集去重
         *      取消全选省份下所有市: 差集
         */
        handleCheckedCitiesChange(old_provide, new_provide, row) {
            let checkCity = [];//全选/取消全选的市id集合

            for(let i=0; i<this.datalist.length; i++) {
                let provideList = this.datalist[i].list;

                for(let key=0; key<provideList.length; key++) {
                    if(provideList[key].name == new_provide) {
                        let cityList = provideList[key].list;

                        cityList.filter(item => {//无需选择不可编辑的数据
                            if(!item.flag) {
                                checkCity.push(item.id);
                            }
                        } );
                    }
                }
            }

            if(old_provide == new_provide) {//全选省份
                this.cityAll = [//当前省下和已选择数据的并集去重
                    ...new Set([...this.cityAll, ...checkCity])
                ];

                this.$set(row, 'length', row.list.length);
            } else { //取消全选省份,考虑其它模版已选择数据
                this.cityAll = this.cityAll.filter(item => !checkCity.includes(item));

                let length = 0;

                for(let key=0; key<row.list.length; key++) {
                    if(row.list[key].flag) {
                        length ++;
                    }
                }
                this.$set(row, 'length', length);
            }

            this.setRemoveGegion(this.checkProvide);//大区状态改变
        },

        /**
         * 分析
         *      全选状态取消选择省份取消大区全选,只改变状态,考虑禁用状态与不禁用状态...
         */
        setRemoveGegion (provide) {
            // console.log(provide, 'provide');
        },

        /**
         * 选择城市
         * 分析(省份全选状态处理)
         *      1.已选择数据长度小于当前省份下城市数据长度，为false
         *      2.已选择数据长度大于当前省份下城市数据长度，取各自数据长度a,b
         *      3.取a与b的并集数组并去重得到长度c, c == a ,此时完全包含，否则不包含
         * 分析2(选择数量计算)
         *      1.获取省份下所有城市数据
         *      2.获取选中的所有数据
         *      3.取交集，得到重复的元素个数即选中的数量
         * @param     {Array}        list           //省份下所有城市数据
         * @param     {String}       city_name      //省份名称
         * @param     {Object}       row            //省份数据,添加数量
         */
        handleCityChange (list, city_name, row) {

            let cityList = list.reduce((cur, next) => {//获取省份下所有市的id数据
                cur.push(next.id);
                return cur;
            }, []);

            //全选状态处理
            if(this.cityAll.length < cityList.length) { //肯定处于不全选状态,取消省份的选择
                this.checkProvide = this.checkProvide.filter(item => ![city_name].includes(item));
            } else {
                let cityAllLength = cityList.length,
                    cityCheckLength = this.cityAll.length;
                let checkCityAll = [
                    ...new Set([...cityList, ...this.cityAll])
                ];

                if(checkCityAll.length == cityCheckLength) {
                    this.checkProvide.push(city_name);
                } else {
                    this.checkProvide = this.checkProvide.filter(item => ![city_name].includes(item));
                }
            }

            //数量统计
            let length = this.cityAll.filter(item => cityList.includes(item)).length;

            this.$set(row, 'length', length);
        },

        /**
         * 鼠标滑过效果
         */
        fnEnterCheck (row, i) {
            this.$set(row, 'flag', true);
            this.now_index = i;
        },

        fnLeaveCheck (row) {
            this.$set(row, 'flag', false);
            this.now_index = -1;
        },

        /**
         * 保存
         *      分析
         *          1:新增状态直接过滤处理
         *          1:编辑需要剔除不可编辑的数据
         */
        fnSave () {
            let cityID = [];

            for(let i=0; i<this.cityAll.length; i++) {
                for(let j=0; j<this.cityList.length;j++){
                    if(this.cityList[j].id == this.cityAll[i]) {
                        cityID.push({
                            name: this.cityList[j].name,
                            id: this.cityList[j].id
                        });
                    }
                }
            }

            if(cityID.length > 0) {
                if(this.type == 'edit') {
                    let list = cityID.filter(item => !this.checkPart.includes(item.id));//过滤不可编辑的数据

                    this.$emit('editData', {
                        data: JSON.stringify(list),
                        index: this.editIndex,
                        param: this.param
                    });
                    this.dialogVisible = false;
                } else {
                    let list = cityID.filter(item => !this.checkPart.includes(item.id));//过滤不可编辑的数据,仅用于配送方式

                    if(list.length == 0) {
                        this.$notify({
                            title: '警告',
                            message: '请至少选择一个城市',
                            type: 'warning'
                        });
                        return;
                    }

                    this.$emit('setData', {
                        data: JSON.stringify(list),
                        type: this.type
                    });
                    this.dialogVisible = false;
                }
            } else {
                this.$notify({
                    title: '警告',
                    message: '请至少选择一个城市',
                    type: 'warning'
                });
            }
        }
    }
};
</script>

<style lang="less" scoped>
.dialogVisible {
    position: fixed;
    left: 0;
    top: 0;
    bottom: 0;
    right: 0;
    margin: auto;
    background: rgba(0,0,0,.6);
    cursor: pointer;
    display: flex;
    z-index: 1000;
    justify-content: center;
    align-items: center;
    .zd-region-dialog {
        width: 640px;
        min-height: 676px;
        box-sizing: border-box;
        background: #ffffff;
        border-right: 4px;
        &-head {
            height: 44px;
            display: flex;
            align-items: center;
            justify-content: space-between;
            padding: 0 10px 0 32px;
            border-bottom: 1px rgba(235,235,235) solid;
            &-title {
                color: #333333;
                font-size: 14px;
                font-weight: 500;
            }
            .el-icon-close {
                color: rgba(194,194,194);
                font-size: 22px;
                font-weight: 500;
            }
        }
        .zd-foot {
            width: 100%;
            height: 36px;
            display: flex;
            align-items: center;
            justify-content: center;
            margin: 40px 0 42px 0;
        }
        .zd-city {
            width: 100%;
            box-sizing: border-box;
            padding: 46px 32px 0 32px;
            display: flex;
            flex-direction: column;
            .zd-list {
                display: flex;
                margin-bottom: 5px;
                &-left {
                    width: 86px;
                    margin-top: 3px;
                }
                &-right {
                    width: calc(100% - 86px);
                    display: flex;
                    flex-wrap: wrap;
                    .zd-list-city {
                        display: flex;
                        position: relative;
                        &-length {
                            color: #EE4E59;
                            margin-top: -1px;
                        }
                        .zd-hover {
                            width: 230px;
                            min-width: 242px;
                            background: #ffffff;
                            position: absolute;
                            left: -24px;
                            top: 24px;
                            z-index: 1000;
                            box-shadow:0px 0px 20px 0px rgba(0,0,0,0.16);
                            display: flex;
                            flex-wrap: wrap;
                            box-sizing: border-box;
                            padding: 12px;
                            border-radius: 5px;
                        }
                        .zd-hover-top {
                           width: 230px;
                            min-width: 242px;
                            background: #ffffff;
                            position: absolute;
                            left: -24px;
                            bottom: 24px;
                            z-index: 1000;
                            box-shadow:0px 0px 20px 0px rgba(0,0,0,0.16);
                            display: flex;
                            flex-wrap: wrap;
                            box-sizing: border-box;
                            padding: 12px;
                            border-radius: 5px;
                        }
                    }
                }
                .el-icon-caret-bottom, .el-icon-caret-top {
                    color: #20A0FF;
                    transition: all 0.3s;
                }
            }
        }
    }
}
</style>

<style lang="less">
.zd-region-dialog {
    .zd-list {
        .el-checkbox {
            width: 86px;
        }
        .el-checkbox-group .el-checkbox {
            margin-right: 0px;
            width: 156px;
            padding: 4px 0;
            margin-bottom: 7px;
        }
        .el-checkbox__label {
            padding-left: 6px;
        }
        // .el-checkbox__inner {
        //     border: 1px #999 solid;
        // }
        .zd-hover, .zd-hover-top{
            .el-checkbox {
                width: 50%;
                display: flex;
                flex-wrap: wrap;
                align-items: center;
            }
            .el-checkbox-group {
                display: flex;
                flex-wrap: wrap;
                width: 100%;
            }
        }
        .zd-checkbox-width .zd-hover .el-checkbox-group .el-checkbox{
            width: auto;
            display: flex;
            flex-wrap: wrap;
        }
        .zd-checkbox-width .zd-hover-top .el-checkbox-group .el-checkbox{
            width: auto;
            display: flex;
            flex-wrap: wrap;
        }
    }
}
</style>